package cn.tedu.csmall.passport.service.imp;

import cn.tedu.csmall.passport.ex.ServiceException;
import cn.tedu.csmall.passport.mapper.AdminMapper;
import cn.tedu.csmall.passport.mapper.AdminRoleMapper;
import cn.tedu.csmall.passport.pojo.dto.AdminLoginDTO;
import cn.tedu.csmall.passport.pojo.entity.Admin;
import cn.tedu.csmall.passport.pojo.dto.AdminAddNewDTO;
import cn.tedu.csmall.passport.pojo.entity.AdminRole;
import cn.tedu.csmall.passport.pojo.vo.AdminListItemVO;
import cn.tedu.csmall.passport.pojo.vo.AdminStandardVO;
import cn.tedu.csmall.passport.security.AdminDetails;
import cn.tedu.csmall.passport.service.IAdminService;
import cn.tedu.csmall.passport.web.ServiceCode;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@Service
public class AdminServiceImpl implements IAdminService {

    /**
     * 生成JWT的key
     */
    @Value("${csmall.jwt.secret-key}")
    private String secretKey;

    /**
     * JWT过期时间
     */
    @Value("${csmall.jwt.duration-in-minute}")
    private Long durationInMinute;


    @Autowired
    AdminMapper adminMapper;

    @Autowired
    AdminRoleMapper adminRoleMapper;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public String login(AdminLoginDTO adminLoginDTO) {
        log.debug("开始处理管理员登录的业务");
        Authentication authentication =
                new UsernamePasswordAuthenticationToken(adminLoginDTO.getUsername()
                        ,adminLoginDTO.getPassword());
        Authentication authenticateResult
                = authenticationManager.authenticate(authentication);
        //将认证结果放入SecurityContext  Security上下文  不用,过时
        //SecurityContextHolder.getContext().setAuthentication(authenticateResult);
        log.debug("认证通过,认证管理器返回的信息{},",authenticateResult);

        //从认证的结果中获取所需数据放入JWT中
        Object principal = authenticateResult.getPrincipal();
        log.debug("认证结果中的当事人类型{}",principal.getClass().getName());
        AdminDetails adminDetails = (AdminDetails)principal;
        String username = adminDetails.getUsername();
        Long id = adminDetails.getId();
        Collection<GrantedAuthority> authorities = adminDetails.getAuthorities();
        String authoritiesJSONString = JSON.toJSONString(authorities);

        //生成JWT数据  需要封装到JWT中的数据
        Map<String,Object> claims = new HashMap<>();
        claims.put("id",id);
        claims.put("username",username);
        claims.put("authoritiesJSONString",authoritiesJSONString);

        log.debug("向JWT中获取id{}",id);
        log.debug("向JWT中获取username{}",username);
        log.debug("向JWT中获取authoritiesJSONString{}",authoritiesJSONString);

        //以下是JWT固定代码
        //过期时间
        Date date = new Date(System.currentTimeMillis() + durationInMinute * 1000 * 60);
        String jwt = Jwts.builder()
                //Header
                .setHeaderParam("alg","HS256")
                .setHeaderParam("typ","JWT")
                //Payload
                .setClaims(claims)
                //Signature
                .setExpiration(date)  //过期时间
                .signWith(SignatureAlgorithm.HS256,secretKey)
                .compact();
        log.debug("生成的JWT:{}",jwt);
        return jwt;
    }


    @Override
    public void addNew(AdminAddNewDTO adminAddNewDTO) {
        log.debug("开始处理注册管理员的业务");
        //查询名称是否已经注册
        int countByUsername = adminMapper.countByUsername(adminAddNewDTO.getUsername());
        if (countByUsername > 0){
            String message = "用户名已经被注册";
            throw new ServiceException(ServiceCode.ERR_CONFLICT,message);
        }
        //查询电话是否已经注册
        int countByPhone = adminMapper.countByPhone(adminAddNewDTO.getPhone());
        if (countByPhone > 0){
            String message = "电话号码已经被注册";
            throw new ServiceException(ServiceCode.ERR_CONFLICT,message);
        }
        //查询邮箱是否已经注册
        int countByEmail = adminMapper.countByEmail(adminAddNewDTO.getEmail());
        if (countByEmail > 0){
            String message = "邮箱已经被注册";
            throw new ServiceException(ServiceCode.ERR_CONFLICT,message);
        }
        //创建admin对象
        Admin admin = new Admin();
        //复制属性
        BeanUtils.copyProperties(adminAddNewDTO,admin);
        //补全属性
        admin.setGmtCreate(new Date());
        admin.setLoginCount(0);
        //TODO 从参数中取出密码,进行加密,再存入Admin对象

        String password = admin.getPassword();
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String encodedPassword = bCryptPasswordEncoder.encode(password);
        admin.setPassword(encodedPassword);

        //执行插入
        int rows = adminMapper.insert(admin);
        if (rows != 1){
            String message = "删除管理员失败,服务器忙,请稍后再尝试!";
            throw new ServiceException(ServiceCode.ERR_INSERT,message);
        }
        //插入管理员与角色的关联数据
        Long [] roleIds = adminAddNewDTO.getRoleIds();
        AdminRole [] adminRoles = new AdminRole[roleIds.length];
        LocalDateTime now = LocalDateTime.now();
        for (int i = 0; i < roleIds.length; i++) {
            AdminRole adminRole = new AdminRole();
            adminRole.setAdminId(admin.getId());
            adminRole.setRoleId(roleIds[i]);
            adminRole.setGmtCreate(now);
            adminRole.setGmtModified(now);
            adminRoles[i] = adminRole;
        }
        rows = adminRoleMapper.insertBatch(adminRoles);
        if (rows != roleIds.length) {
            String message = "添加管理员失败，服务器忙，请稍后再次尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }
    }

    @Override
    public void deleteById(Long id) {
        log.debug("开始处理[删除管理员]的业务,参数:{}",id);
        //id值为1的管理员不允许删除 root
        if (id.equals(1)){
            String message = "删除管理员失败,尝试删除的数据不存在";
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,message);
        }
        //查询要删除的管理员是否存在
        AdminStandardVO queryResult = adminMapper.getStandardById(id);
        //是否为null
        if (queryResult == null){
            String message = "删除管理员失败,尝试删除的数据不存在";
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,message);
        }
        
        //调用mapper对象的deleteById()方法执行删除
        log.debug("即将执行删除,参数:{}",id);
        int rows = adminMapper.deleteById(id);
        if (rows != 1){
            String message = "删除管理员失败,服务器忙,请稍后再尝试!";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_DELETE,message);
        }

        // 删除管理员与角色的关联数据
        rows = adminRoleMapper.deleteByAdminId(id);
        if (rows < 1){
            String message = "删除管理员失败,服务器忙,请稍后再尝试!";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_DELETE,message);
        }
    }

    @Override
    public void setEnable(Long id) {
        updateEnableById(id,1);
    }

    @Override
    public void setDisable(Long id) {
        updateEnableById(id,0);
    }

    private void updateEnableById(Long id, Integer enable)
    {
        log.debug("开始处理[更新管理员是否启用]的业务,参数:{}",id);
        //id值为1的管理员不允许删除 root
        if (id.equals(1)){
            String[] s = {"禁用","启用"};
            String message = s[enable] + "管理员失败,尝试修改的数据不存在";
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,message);
        }
        // 查询要删除的管理员是否存在
        AdminStandardVO queryResult = adminMapper.getStandardById(id);
        //是否为null
        if (queryResult == null){
            String[] s = {"禁用","启用"};
            String message = s[enable] + "管理员失败,尝试修改的数据不存在";
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,message);
        }
        //判断enable和参数enable1是否相同
        if (queryResult.getEnable().equals(enable)){
            String[] s = {"禁用","启用"};
            String message = s[enable] + "管理员失败,改管理员已经" + s[enable];
            throw new ServiceException(ServiceCode.ERR_CONFLICT,message);
        }
        Admin admin = new Admin();
        admin.setId(id);
        admin.setEnable(enable);
        int rows = adminMapper.update(admin);
        if (rows != 1){
            String[] s = {"禁用","启用"};
            String message = s[enable] + "管理员失败,尝试修改的数据不存在";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE,message);
        }
    }

    @Override
    public List<AdminListItemVO> list() {
        log.debug("开始处理查询管理员列表的业务");
        List<AdminListItemVO> list = adminMapper.list();
        Iterator<AdminListItemVO> iterator = list.iterator();
        while (iterator.hasNext()){
            AdminListItemVO item = iterator.next();
            if (item.getId() == 1){
                iterator.remove();
                break;
            }
        }
        return list;
    }
}
